<?php

namespace app\qsapi\service;

use app\qsapi\model\BoxGame;
use app\qsapi\model\BoxYunUserMachine;
use app\qsapi\model\Member;
use think\cache\driver\Redis;
use think\Collection;
use think\Exception;

class YunService extends BaseService
{

    /**
     * Desc : 获取商户客户端临时clientToken与clientSecretKey接口
     * User : steven
     * Date : 2024-03-22 13:46
     */
    public static function getYunTokenKey($member_id, $params): array
    {
        $redis = new Redis(getRedisConfig());
        if ($redis->has('yun_user_token_key_' . $member_id)) {
            $redisData                   = $redis->get('yun_user_token_key_' . $member_id);
            $redisData                   = json_decode($redisData, true);
            $redisData['leisureMachine'] = self::getLeisureMachine($member_id);
            return [
                'code' => 200,
                'msg'  => 'success',
                'data' => $redisData
            ];
        }
        $postUrl = Env('yun.api_url') . "/yun/user/token/client/auth";

        $data = [
            't'      => (string)time(),
            'os'     => $params['os'],
            'userId' => $member_id,
        ];

        $header   = self::commonHeader($data);
        $header[] = 'user_id: ' . (string)$member_id;

        unset($data['os']);
        unset($data['userId']);

        $result = self::commonSign($postUrl, $header, $data);
        if ($result['code'] == 200) {
            $redis->set('yun_user_token_key_' . $member_id, json_encode($result['data']), 7100);
        }

        $result['data']['leisureMachine'] = self::getLeisureMachine($member_id);
        return $result;
    }

    /**
     * Desc : 获取空闲机器
     * User : you name
     * Date : 2024-03-25 09:53
     * @param $member_id
     * @return BoxYunUserMachine[]|array|Collection
     */
    public static function getLeisureMachine($member_id)
    {
        $where[] = ['member_id', '=', $member_id];
        $where[] = ['member_child_id', '=', ''];
        $where[] = ['running_status', '=', 0];
        $where[] = ['mark', '=', 1];
        $where[] = ['valid_end_time', '>', date('Y-m-d H:i:s')];

        $arr = (new BoxYunUserMachine())->field('id,member_id,facilities_id,user_phone_id,valid_end_time')->where($where)->select();
        return $arr->toArray() ?? [];
    }


    /**
     * @Notes:用户设备列表
     * @Interface getUserFacilitiesList
     * @param $member_id
     * @param $params
     * @return bool|mixed|string
     */
    public static function getUserFacilitiesList($member_id, $params)
    {
        $postUrl = Env('yun.api_url') . "/user/facilities/list";

        $data = [
            't'      => (string)time(),
            'userId' => $member_id,
            'os'     => $params['os'],
        ];
        if (isset($params['facilitiesId']) && !empty($params['facilitiesId'])) {
            $data['facilitiesId'] = $params['facilitiesId'];
        }
        if (isset($params['runningStatus']) && !empty($params['runningStatus'])) {
            $data['runningStatus'] = $params['runningStatus'];
        }
        if (isset($params['status']) && !empty($params['status'])) {
            $data['status'] = $params['status'];

        }

        $header = self::commonHeader($data);

        unset($data['os']);
        $postData = http_build_query($data);
        $postData .= '&sign=' . self::getSign($data); // 添加签名字段

        $result = self::requestAPI($postUrl, $postData, $header);
        return json_decode($result, true);
    }

    /**
     * @Notes:获取用户userPhone对应云机
     * @Interface getYunUserPhone
     * @param $data
     * @param $userPhoneId
     * @return mixed
     */
    public static function getUserPhoneYun($data,$userPhoneId){
        foreach ($data as $yunItem) {
            if ($yunItem['userPhoneId'] == $userPhoneId) {
                return $yunItem;
            }
        }
    }

    /**
     * @Notes:分配用户设备
     * @Interface userFacilitiesDistribute
     * @param $member_id
     * @param $params
     * @return array
     */
    public static function userFacilitiesDistribute($member_id, $params): array
    {
        $postUrl = Env('yun.api_url') . "/user/facilities/distribute";
        $data    = [
            't'            => (string)time(),
            'userId'       => (string)$member_id,
            'os'           => $params['os'],
            'amount'       => (int)$params['amount'],
            'multiplex'    => (int)$params['multiplex'],
            'requestId'    => (string)$params['requestId'],
            'validEndTime' => (string)$params['validEndTime'],
        ];
        $header  = self::commonHeader($data);

        unset($data['os']);
        $postData = http_build_query($data);
        $postData .= '&sign=' . self::getSign($data); // 添加签名字段

        $result = self::requestAPI($postUrl, $postData, $header);
        return json_decode($result, true);
    }


    /**
     * @Notes:续费用户设备
     * @Interface userFacilitiesRenewal
     * @param $member_id
     * @param $params
     * @return array
     */
    public static function userFacilitiesRenewal($member_id, $params): array
    {
        $postUrl = Env('yun.api_url') . "/user/facilities/renewal";
        $data    = [
            't'            => (string)time(),
            'userId'       => $member_id,
            'os'           => $params['os'],
            'userPhoneId'  => $params['userPhoneId'],
            'validEndTime' => $params['validEndTime'],
        ];
        $header  = self::commonHeader($data);

        unset($data['os']);
        $postData = http_build_query($data);
        $postData .= '&sign=' . self::getSign($data); // 添加签名字段

        $result = self::requestAPI($postUrl, $postData, $header);
        return json_decode($result, true);
    }


    /**
     * Desc : 用户重启设备
     * User : you name
     * Date : 2024-03-19 15:24
     * @param $member_id
     * @param $params
     * @return array
     */
    public static function getFacilitiesRestart($member_id, $params): array
    {
        $notice = $params['notice'] ?? false;
        if (empty($params['os']) || empty($params['userPhoneId'])) {
            return [
                'code' => 0,
                'msg'  => '参数错误',
                'data' => []
            ];
        }

        $postUrl = Env('yun.api_url') . "/user/facilities/yun/user/restart";
        $data    = [
            't'           => (string)time(),
            'userId'      => (string)$member_id,
            'os'          => (string)$params['os'],
            'userPhoneId' => (string)$params['userPhoneId'],
        ];

        if (!empty($notice)) {
            $data['notice'] = true;
        }

        $header = self::commonHeader($data);

        unset($data['os']);
        unset($data['userId']);

        return self::commonSign($postUrl, $header, $data);
    }

    /**
     * Desc : 获取重启记录
     * User : you name
     * Date : 2024-03-19 15:24
     * @param $member_id
     * @param $params
     * @return array
     */
    public static function getRestartLog($member_id, $params): array
    {
        $postUrl = Env('yun.api_url') . "/user/facilities/yun/user/restart/record";
        $data    = [
            't'           => (string)time(),
            'userId'      => $member_id,
            'os'          => $params['os'],
            'notice'      => $params['notice'] ?? false,
            'userPhoneId' => $params['userPhoneId'],
        ];
        $header  = self::commonHeader($data);

        unset($data['os']);
        unset($data['userId']);

        return self::commonSign($postUrl, $header, $data);
    }

    /**
     * Desc : 冻结,解冻用户设备
     * User : you name
     * Date : 2024-03-19 15:46
     * @param $member_id
     * @param $params
     * @return array
     */
    public static function setFacilitiesFreeze($member_id, $params): array
    {
        $postUrl = Env('yun.api_url') . "/user/facilities/freeze";
        $data    = [
            't'           => (string)time(),
            'userId'      => $member_id,
            'os'          => $params['os'],
            'freeze'      => $params['freeze'],
            'userPhoneId' => $params['userPhoneId'],
        ];
        $header  = self::commonHeader($data);

        unset($data['os']);

        return self::commonSign($postUrl, $header, $data);
    }

    /**
     * Desc : 回收用户设备
     * User : you name
     * Date : 2024-03-19 15:50
     * @param $member_id
     * @param $params
     * @return array
     */
    public static function setFacilitiesRecycle($member_id, $params): array
    {
        $postUrl = Env('yun.api_url') . "/user/facilities/recycle";
        $data    = [
            't'           => (string)time(),
            'userId'      => $member_id,
            'os'          => $params['os'],
            'userPhoneId' => $params['userPhoneId'],
        ];
        $header  = self::commonHeader($data);

        unset($data['os']);

        return self::commonSign($postUrl, $header, $data);
    }

    /**
     * Desc : 查询云机运行状态类型
     * User : you name
     * Date : 2024-03-19 13:44
     * @param $member_id
     * @param $params
     * @return array
     */
    public static function getFacilitiesStatus($member_id, $params): array
    {
        $postUrl = Env('yun.api_url') . "/user/facilities/get/status";
        $data    = [
            't'      => (string)time(),
            'userId' => $member_id,
            'os'     => $params['os'],
        ];
        $header  = self::commonHeader($data);

        unset($data['os']);
        unset($data['userId']);

        return self::commonSign($postUrl, $header, $data);
    }

    /**
     * Desc : 设置挂机时长
     * User : you name
     * Date : 2024-03-19 14:23
     * @param $member_id
     * @param $params
     * @return array
     */
    public static function setFacilitiesHangUpTime($member_id, $params): array
    {
        $postUrl = Env('yun.api_url') . "/user/facilities/hang/up/time";
        $data    = [
            't'           => (string)time(),
            'userId'      => $member_id,
            'os'          => $params['os'],
            'pkg'         => $params['pkg'], //游戏包名
            'hangUpTime'  => $params['hangUpTime'],   //挂机时长单位（秒）
            'userPhoneId' => $params['userPhoneId'], //用户设备id
        ];
        $header  = self::commonHeader($data);

        unset($data['os']);
        unset($data['userId']);

        return self::commonSign($postUrl, $header, $data);
    }


    /**
     * Desc : 关闭当前云游Android、IOS sdk端运行游戏
     * User : you name
     * Date : 2024-03-19 16:01
     * @param $member_id
     * @param $params
     * @return array
     */
    public function setFacilitiesClosedGame($member_id, $params): array
    {
        $fid         = $params['facilitiesId'] ?? 0;
        $pkg         = $params['pkg'] ?? '';
        $userPhoneId = $params['userPhoneId'] ?? '';
        if (empty($params['os']) || empty($params['userPhoneId']) || empty($params['type'])) {
            return [
                'code' => 0,
                'msg'  => '参数错误',
                'data' => []
            ];
        }

        $platform = $this->getPlatform() == 'ios' ? 1 : 2;
        if($platform == 1 ){
            $postUrl = Env('yun.api_url') . "/user/facilities/closed/game";
        }else{
            $postUrl = Env('yun.api_url') . "/user/facilities/sdk/closed/game";
        }

        $data    = [
            't'           => (string)time(),
            'userId'      => $member_id,
            'os'          => (string)$params['os'],
            'userPhoneId' => (string)$params['userPhoneId'], //用户设备id
            'type'        => (int)$params['type'] ?? 2,   //类型（1：商户账号上所有正在运行游戏的云机全部断开(慎用)，2：根据参数断开,参数规则是and查询）
        ];
        if (isset($pkg) && !empty($pkg)) {
            $data['pkg'] = $params['pkg'];
        }
        if (isset($fid) && !empty($fid)) {
            $data['facilitiesId'] = $params['facilitiesId'];
        }
        $header = self::commonHeader($data);

        unset($data['os']);
        unset($data['userId']);


        $postData = http_build_query($data);
        $postData .= '&sign=' . self::getSign($data); // 添加签名字段

        $result = self::requestAPI($postUrl, $postData, $header);
        $result = json_decode($result, true);
        if ($result['data'] != true) {
            return api_message($result['data'], $result['message'], 0);
        }

        //解绑本地云机的参数
        self::unbindLocalYunMachine($member_id, $userPhoneId);

        return api_message($result['data'], $result['message']);
    }

    /**
     * Desc : 解绑本地云机
     * User : you name
     * Date : 2024-03-29 14:18
     * @param $member_id
     * @param $user_phone_id
     */
    public static function unbindLocalYunMachine($member_id, $user_phone_id)
    {
        try {
            if (empty($user_phone_id) || empty($member_id)) {
                return;
            }
            $where[]      = ['member_id', '=', $member_id];
            $where[]      = ['user_phone_id', '=', $user_phone_id];
            $machineModel = new BoxYunUserMachine();
            $machineModel->where($where)->update(['game_id' => 0, 'member_child_id' => 0, 'running_status' => 0]);
        } catch (Exception $e) {
            return;
        }

    }

    /**
     * Desc : 自动分配云机,并返回游戏的启动参数
     * User : you name
     * Date : 2024-03-25 10:48
     * @param $member_id
     * @param $params
     * @return array
     */
    public static function allotYunMachine($member_id, $params): array
    {
        //外部包启动判定
        $game_id = $params['game_id'] ?? 0;
        $child_id = $params['member_child_id'] ?? 0;
       $user_phone_id = $params['user_phone_id'] ?? '';
        if(empty($game_id)){
            return api_message([], '游戏参数错误', 0);
        }

        $gameInfo = (new BoxGame())->where('id', $game_id)->field('is_yun,yun_hang_up_bag,open_type')->find()->toArray();

        $arr = [];
        //原生启动的方式
        if($gameInfo['open_type'] == 0){
            if(empty($child_id)){
                return api_message([], '小号参数错误', 0);
            }

            //判定当前小号是否为主号下的账号
            $member_pid = (new Member())->where('id', $params['member_child_id'])->value('pid');
            if ($member_id != $member_pid) {
                return api_message([], '小号有误', 0);
            }

            //获取云挂机包名
            // $gameBag = (new BoxGame())->where('id', $params['game_id'])->field('is_yun,yun_hang_up_bag')->find()->toArray();
            //获取云挂机启动参数
            $startParams = (new GameService)->yunCreateStartup($member_id, $params['game_id'], $params['member_child_id'],$params);
            if ($startParams['code'] != 200) {
                return api_message([], '游戏启动参数有误,' . $startParams['msg'], 0);
            }
            $startParams = $startParams['data'] ?? [];


            //获取当前游戏,当前账号的挂机状态
            $gameStatus = (new BoxYunUserMachine())->field('user_phone_id,facilities_id,running_status')->where(['game_id' => $params['game_id'], 'member_id' => $member_id, 'member_child_id' => $params['member_child_id']])->where('valid_end_time', '>', date('Y-m-d H:i:s'))->find();

            //有绑定关系, 直接返回游戏的启动参数
            if (!empty($gameStatus)) {
                return api_message(array_merge($gameStatus->toArray(), $startParams, $gameInfo), '当前游戏正在运行中');
            }


            $where[] = ['member_id', '=', $member_id];
            $where[] = ['game_id', '=', 0];
            $where[] = ['member_child_id', '=', 0];
            $where[] = ['running_status', '=', 0];
            $where[] = ['valid_end_time', '>', date('Y-m-d H:i:s')];
            $arr     = (new BoxYunUserMachine())->field('id,user_phone_id,facilities_id')->where($where)->select()->toArray() ?? [];
            if (empty($arr)) {
                return api_message([], '你的云手机均在使用中,请购买新的云手机或者将其中一台关闭以后再进行挂机!', 101);
            }
            $id = $arr[0]['id'];


            //分配小号
            $param        = ['game_id' => $params['game_id'], 'member_child_id' => $params['member_child_id']];
            $machineModel = new BoxYunUserMachine();
            $result       = $machineModel->where('id', $id)->update($param);
            if (!$result) return api_message([], '分配失败', 0);
            $machine = [
                'user_phone_id' => $arr[0]['user_phone_id'] ?? '',
                'facilities_id' => $arr[0]['facilities_id'] ?? '',
            ];
            $arr     = array_merge($machine, $startParams, $gameInfo);
        }else if ($gameInfo['open_type'] == 1){  //外部跳转启动

            //获取当前游戏,当前账号的挂机状态
            $gameStatus = (new BoxYunUserMachine())->field('user_phone_id,facilities_id,running_status')->where(['game_id' => $params['game_id'], 'member_id' => $member_id, 'user_phone_id' => $user_phone_id])->where('valid_end_time', '>', date('Y-m-d H:i:s'))->find();
            // $redis = new Redis(getRedisConfig());
            // $keyPhone = 'userPhoneId:game_id:'.$params['game_id'].'member_id:'.$member_id;
            // $gameStatus = $redis->get($keyPhone);
            //有绑定关系, 直接返回游戏的启动参数
            if (!empty($gameStatus)) {
                // $gameStatus = json_decode($gameStatus,true);
                // $redis->rm($keyPhone);
                return api_message(array_merge($gameStatus->toArray(), $gameInfo), '当前游戏正在运行中');
            }

            //外部单包启动云挂机
            $where[] = ['member_id', '=', $member_id];
            $where[] = ['game_id', '=', 0];
            $where[] = ['running_status', '=', 0];
            $where[] = ['valid_end_time', '>', date('Y-m-d H:i:s')];
            $arr     = (new BoxYunUserMachine())->field('id,user_phone_id,facilities_id')->where($where)->select()->toArray() ?? [];
            if (empty($arr)) {
                return api_message([], '你的云手机均在使用中,请购买新的云手机或者将其中一台关闭以后再进行挂机!', 101);
            }

            $id = $arr[0]['id'];
            //分配小号
            $param        = ['game_id' => $params['game_id']];
            $machineModel = new BoxYunUserMachine();
            $result       = $machineModel->where('id', $id)->update($param);
            if (!$result) return api_message([], '分配失败', 0);
            $machine = [
                'user_phone_id' => $arr[0]['user_phone_id'] ?? '',
                'facilities_id' => $arr[0]['facilities_id'] ?? '',
            ];

            $arr     = array_merge($machine,  $gameInfo);
            // $redis->set($keyPhone, json_encode($arr),3);
        }
        return api_message($arr, '分配成功');
    }

    /**
     * Desc : 获取云机列表状态
     * User : you name
     * Date : 2024-04-02 22:13
     * @param $member_id
     * @param $game_id
     * @return array
     */
    public static function getYunMachineList($member_id, $game_id): array
    {
        if (empty($game_id)) {
            return api_message([], '游戏参数有误!', 0);
        }
        //获取当前设别是否都在使用中
        $machineList = (new BoxYunUserMachine())->where(['member_id' => $member_id])->where('valid_end_time', '>', date('Y-m-d H:i:s'))->select()->toArray();
        if (empty($machineList)) return api_message([], '你还没有云机哦,快去畅享一键云挂机吧!', 100);

        //获取当前游戏的启动方式
        $open_type = BoxGame::where('id', $game_id)->value('open_type');
        $map = [];
        if($open_type == 1){
            $map[] = ['member_id', '=', $member_id];
            $map[] = ['game_id', '=', 0];
        }else{
            $map[] = [['game_id' ,'=', $game_id], ['member_id' ,'=', $member_id]];
        }

        $new_result = (new BoxYunUserMachine())->where($map)->where('valid_end_time', '>', date('Y-m-d H:i:s'))->find();
        if($open_type == 1 && empty($new_result)) return api_message([], '你的云手机均在使用中,请购买新的云手机或者将其中一台关闭以后再进行挂机!', 101);

        $result = array_column($machineList, 'game_id');
        //判定当前数组如果没有0的情况下,返回true,说明所有的设被分配了游戏ID
        $result = array_reduce($result, function ($result, $value) {
            return $result && $value !== 0;
        }, true);
        if ($result) {
            return api_message([], '你的云手机均在使用中,请购买新的云手机或者将其中一台关闭以后再进行挂机!', 101);
        }
        return api_message([], '获取成功');
    }

    /**
     * Desc : IOS端获取访问的URL
     * User : you name
     * Date : 2024-03-27 09:07
     * @return array
     */
    public static function getYunIosUrl(): array
    {
        return api_message(['h5_url' => env('yun.box_ios_yun_h5_url')], '获取成功');
    }


    /**
     * @Notes:根据userPhoneId频率截取图片
     * @Interface getYunScreenshot
     * @param $member_id
     * @param $params
     * @return array
     */
    public static function getYunScreenshot($member_id, $params): array
    {
        $postUrl = Env('yun.api_sc_url') . "/v1/user/device/v1/frequency/screenshot";

        $data   = [
            't'             => (string)time(),
            'userId'        => $member_id,
            'os'            => $params['os'],
            'userPhoneId'   => $params['userPhoneId'],
            'method'        => (string)'PUT',
            'signedUrl'     => $params['signedUrl'],
            'quality'       => (int)85,
            'cycleInterval' => (int)6,
            'cycleTimes'    => (int)1,
        ];
        $header = [
            'Content-Type: application/json',
            'ACCESS_TOKEN:' . Env('yun.access_token'),
            'phone_id:' . $data['userId'],
            'os:' . $data['os'],
        ];
        unset($data['os']);
        $data['sign'] = self::getSign($data); // 添加签名字段
        $result       = self::requestAPI($postUrl, json_encode($data), $header);
        $result       = json_decode($result, true);
        if ($result['code'] != 1) {
            return api_message($result['data'] ?? [], $result['message'] ?? '', 0);
        }
        return api_message($result['data'] ?? [], $result['message'] ?? '');
    }


    /**
     * Desc : 获取公共的header头信息
     * User : you name
     * Date : 2024-03-19 13:40
     * @param $data
     * @return string[]
     */
    public static function commonHeader($data): array
    {
        return [
            'Content-Type: application/x-www-form-urlencoded',
            'ACCESS_TOKEN:' . Env('yun.access_token'),
            'phone_id:' . $data['userId'],
            'os:' . $data['os'],
        ];
    }

    /**
     * Desc : 公共的数据请求返回
     * User : you name
     * Date : 2024-03-19 15:35
     * @param $postUrl
     * @param $header
     * @param array $data
     * @return array
     */
    public static function commonSign($postUrl, $header, array $data = []): array
    {
        $postData = http_build_query($data);
        $postData .= '&sign=' . self::getSign($data); // 添加签名字段
        $result   = self::requestAPI($postUrl, $postData, $header);
        $result   = json_decode($result, true);
        if ($result['data'] != true) {
            return api_message($result['data'], $result['message'], 0);
        }
        return api_message($result['data'], $result['message']);
    }


    public static function getSign($params)
    {
        // 对参数值进行排序
        $values = array_values($params);
        array_walk($values, function (&$value) {
            $value = urlencode($value);
        });

        sort($values, SORT_STRING);

        // 拼接参数字符串
        $paramString = implode('&', $values);

        // 拼接 secret_key
        $secretKey   = Env('yun.secret_key'); // 替换为真实的 secret_key
        $paramString .= '&' . $secretKey;

        // 计算 MD5 值作为 sign
        $sign = md5($paramString);

        // 输出最终的 sign 值
        return $sign;

    }


    public static function requestAPI($url, $data, $header)
    {
        // 模拟提交数据函数
        $curl = curl_init(); // 启动一个CURL会话
        curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); // 从证书中检查SSL加密算法是否存在
//        curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
        curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer
        curl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data); // Post提交的数据包
        curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
//        curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
        $tmpInfo = curl_exec($curl); // 执行操作
        if (curl_errno($curl)) {
            echo 'Errno' . curl_error($curl);//捕抓异常
        }
        curl_close($curl); // 关闭CURL会话
        return $tmpInfo; // 返回数据，json格式
    }

}
